﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using System.Xml;

namespace WebCrawling.Data.Extracting
{
    public class Rules
    {
        #region Field

        private static Dictionary<string, Rule> mDicRules = new Dictionary<string, Rule>();
        private static Rules mRule;
        #endregion

        #region Properties
        public static Rules Instance
        {
            get
            {
                if (mRule == null)
                {
                    mRule = new Rules();
                    LoadRules();
                }
                return mRule;
            }
        }

        public static void Reset()
        {
            mDicRules.Clear();
            mRule = null;
        }

        public Dictionary<string, Rule> DicRules
        {
            get
            {
                return mDicRules;
            }
        }

        #endregion

        #region Method

        public bool Contain(Rule rule)
        {
            bool blResult = false;

            foreach (Rule s in mDicRules.Values)
            {
                if (rule.Name == s.Name)
                {
                    blResult = true;
                    break;
                }
            }

            return blResult;
        }
        public Rule Find(string Name)
        {
            Rule rule = null;

            foreach (string key in mDicRules.Keys)
            {
                rule = mDicRules[key];

                if (rule.Name == Name)
                {
                    return rule;
                }
            }
            return null;
        }

        private void RemoveRule(string Name)
        {
            Rule rule = null;

            foreach (string key in mDicRules.Keys)
            {
                rule = mDicRules[key];

                if (rule.Name == Name)
                {
                    mDicRules.Remove(key);
                    break;
                }
            }
        }

        private void AddRule(Rule rule)
        {
            if (!Contain(rule))
            {
                mDicRules.Add(rule.Name, rule);
            }
        }

        public void Clear()
        {
            mDicRules.Clear();
        }

        public static string GetValueFromXML(XmlNode node, string key, NodeType type = NodeType.Attribute)
        {
            string value = string.Empty;
            if (type == NodeType.Attribute)
            {
                if (node.Attributes[key] != null)
                {
                    value = node.Attributes[key].Value.Trim();
                }
            }
            else if (type == NodeType.SingleNode)
            {
                if (node.SelectSingleNode(key) != null)
                {
                    value = node.SelectSingleNode(key).InnerText.Trim();
                }
            }
            if (key == "Status" && value == string.Empty)
            {
                value = "3";
            }
            return value;
        }

        private static Dictionary<string, Field> GetFieldsFromXML(XmlNode node)
        {
            Dictionary<string, Field> fieldAttributes = new Dictionary<string, Field>();

            foreach (XmlNode child in node.SelectNodes("Field"))
            {
                Field field = new Field();
                field.Name = child.Attributes["Name"].Value.Trim();
                field.Regex = child.InnerText.Trim();
                field.RemoveHtmlTags = bool.Parse(child.Attributes["RemoveHtmlTags"].Value.Trim());
                fieldAttributes.Add(field.Name, field);
            }
            return fieldAttributes;
        }

        private static Dictionary<string, URLRule> GetURLRulesFromXML(XmlNode node)
        {
            Dictionary<string, URLRule> UrlRules = new Dictionary<string, URLRule>();

            foreach (XmlNode child in node.SelectNodes("URLRule"))
            {
                URLRule UrlRule = new URLRule();
                UrlRule.Name = child.Attributes["Name"].Value.Trim();
                UrlRule.UrlPrefix = child.Attributes["UrlPrefix"].Value.Trim();
                UrlRule.Category = child.Attributes["Category"] == null ? "" : child.Attributes["Category"].Value.Trim();
                UrlRule.SaveFormatType = (SaveFormatType)(Enum.Parse(typeof(SaveFormatType), child.Attributes["SaveFormatType"].Value.Trim()));
                UrlRule.UrlFormat = child.InnerText.Trim();

                UrlRules.Add(UrlRule.UrlPrefix, UrlRule);
            }
            return UrlRules;
        }

        private static void LoadRules()
        {
            XmlDocument doc = new XmlDocument();
            string filename = "Config/Rules.xml";
            doc.Load(filename);

            Rule rule = null;

            XmlNodeList rules = doc.SelectNodes("Rules/Rule");

            foreach (XmlNode mrule in rules)
            {

                foreach (KeyValuePair<string, URLRule> UrlRule in GetURLRulesFromXML(mrule))
                {
                    rule = new Rule();
                    rule.Name = UrlRule.Key;
                    rule.Charset = GetValueFromXML(mrule, "Charset");
                    rule.Status = (Status)(Enum.Parse(typeof(Status), GetValueFromXML(mrule, "Status")));
                    rule.Type = (SiteType)(Enum.Parse(typeof(SiteType), GetValueFromXML(mrule, "Type")));
                    rule.LinksRegex = GetValueFromXML(mrule, "LinksRegex", NodeType.SingleNode);
                    rule.FilterChars = GetValueFromXML(mrule, "FilterChars", NodeType.SingleNode);
                    rule.Fields = GetFieldsFromXML(mrule);
                    rule.URLRule = UrlRule.Value;
                }
                mDicRules.Add(rule.Name, rule);
            }
        }
        #endregion

    }

    public class Rule
    {
        public string Name
        {
            get;
            set;
        }

        public string Charset
        {
            get;
            set;
        }

        public Status Status
        {
            get;
            set;
        }

        public string LinksRegex
        {
            get;
            set;
        }

        public string FilterChars
        {
            get;
            set;
        }

        public SiteType Type
        {
            get;
            set;
        }

        public DateTime StartDate
        {
            get;
            set;
        }

        public DateTime EndDate
        {
            get;
            set;
        }

        public Dictionary<string, Field> Fields
        {
            get;
            set;
        }

        public URLRule URLRule
        {
            get;
            set;
        }

        public string CrawledURL
        {
            get;
            set;
        }

        public string LinkedURL
        {
            get;
            set;
        }
    }

    public class Field
    {
        public string Name
        {
            get;
            set;
        }
        public string Regex
        {
            get;
            set;
        }
        public bool RemoveHtmlTags
        {
            get;
            set;
        }
    }

    public class URLRule
    {
        public string Name
        {
            get;
            set;
        }

        public string UrlPrefix
        {
            get;
            set;
        }
        public string Category
        {
            get;
            set;
        }
        public SaveFormatType SaveFormatType
        {
            get;
            set;
        }

        public string UrlFormat
        {
            get;
            set;
        }
    }

}
